<?php
/**
 *
 * 工程启动加载类
 *
 * @author     liang<lang@vip.deyi.com>
 * @since      2015年5月21日
 * @copyright  deyi.com
 */

namespace Apps;

use Apps\Common\Constant\CacheTimeoutConstant;
use Apps\Common\Logger\FileLogger;
use Deyi\Functions\DateTimeFunction;
use Deyi\Functions\UserFunction;
use Phalcon\Cache\Backend\File;
use Phalcon\Cache\Frontend\Data;
use Phalcon\Config;
use Phalcon\Config\Adapter\Ini;
use Phalcon\Crypt;
use Phalcon\Db\Adapter\Pdo\Mysql;
use Phalcon\DiInterface;
use Phalcon\Loader;
use Phalcon\Mvc\Application;
use Phalcon\Mvc\Router;
use Phalcon\Session\Adapter\Files;
use Phalcon\Session\Adapter\Libmemcached as SessionCache;
use Vendor\GetuiPush\GetuiPush;
use Vendor\Pheanstalk\Pheanstalk;

/**
 * Class BootStrap
 * @package Apps
 */
class BootStrap extends Application
{

    private static $_config;

    private static $_moduleNames;

    public function __construct(DiInterface $di)
    {
        $this->di = $di;

        // 分批加载启动模块
        $bootstraps = [
            'config',
            'module',
            'loader',
            'router',
            'logger',
            'db',
            'redis',
            'memcached',
            'fileCache',
            'session',
            'crypt',
          //  'beanstalkd',
            'init'
        ];

        foreach ($bootstraps as $v) {
            $this->$v();
        }

        parent::__construct($di);
    }

    protected function module()
    {
        self::$_moduleNames = explode(',', self::$_config->project->modules);

        $moduleArray = [];

        foreach (self::$_moduleNames as $v) {
            $moduleArray[$v] = [
                'className' => "Apps\\$v\\Module",
                'path' => __DIR__ . "/$v/Module.php"
            ];
        }

        $this->registerModules($moduleArray);
    }

    protected function config()
    {
        $this->di->setShared('config', function () {
            $appConfig = new Ini(ROOT_PATH . '/conf/application.ini');
            $routerConfigTmp = new Ini(ROOT_PATH . '/conf/router.ini');
            $routerConfig = new Config([
                'router' => $routerConfigTmp->toArray()
            ]);

            $appConfig = $appConfig->merge($routerConfig);

            // 处理memcached配置参数
            if (isset($appConfig->memcached->host)) {
                $memcachedCluster = explode(',', $appConfig->memcached->host);

                $memcachedArr = [];

                foreach ($memcachedCluster as $v) {
                    $tmp = explode(':', $v);
                    $memcachedArr[] = [
                        'host' => $tmp[0],
                        'port' => $tmp[1],
                        'weight' => 1
                    ];
                }

                $appConfig['memcached'] = $memcachedArr;
            }

            $db = [];
            // 处理mysql配置参数
            foreach ($appConfig as $name => $value) {
                $tmp = explode(':', $name);

                if ($tmp[0] == 'mysql') {

                    $dbOptions = [
                        \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . strtoupper($value->charset),
                        \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                    ];

                    if (RUN_MODE == 'CLI') {
                        $dbOptions[\PDO::ATTR_TIMEOUT] = 3;
                    } else {
                        $dbOptions[\PDO::ATTR_PERSISTENT] = 1;
                    }

                    $db[$tmp[2] . '_' . $tmp[1]] = [
                        "host" => $value->host,
                        "dbname" => $value->dbname,
                        "port" => $value->port,
                        "username" => $value->user,
                        "password" => $value->password,
                        "read" => isset($value->read) ? $value->read : $appConfig->default->masterread,
                        "options" => $dbOptions
                    ];
                }
            }

            $appConfig['mysql'] = $db;

            return $appConfig;
        });

        self::$_config = $this->di->get('config');
    }

    protected function router()
    {
        //执行耗时计时开始
        DateTimeFunction::getExecutionTime();

        $this->di->set('router', function () {

            $router = new Router(isset(self::$_config->default->router) ? true : false);

            $router->removeExtraSlashes(true);

            // 设置默认路由路径
            $router->add('/:module/:controller/:action', [
                'module' => 1,
                'controller' => 2,
                'action' => 3
            ])->convert('module', function ($module) {
                return ucfirst(strtolower($module));
            })->convert('controller', function ($controller) {
                return ucfirst(strtolower($controller));
            })->convert('action', function ($action) {
                return ucfirst(strtolower($action));
            });

            if (isset(self::$_config->default->notfound)) {
                // 设置未找到路由时指向的路径
                $tmp = explode(':', self::$_config->default->notfound);
                $router->notFound([
                    'module' => $tmp[0],
                    'controller' => $tmp[1],
                    'action' => $tmp[2]
                ]);
            }

            if (!empty(self::$_config['router'])) {
                foreach (self::$_config['router'] as $name => $value) {
                    $split = explode(':', $name);

                    if (count($split) !== 3) {
                        continue;
                    }

                    switch ((isset($value->method) ? strtolower($value->method) : '')) {
                        case 'get':
                            $router->addGet($value->url, [
                                'module' => $split[0],
                                'controller' => $split[1],
                                'action' => $split[2]
                            ]);
                            break;
                        case 'post':
                            $router->addPost($value->url, [
                                'module' => $split[0],
                                'controller' => $split[1],
                                'action' => $split[2]
                            ]);
                            break;
                        default:
                            $router->add($value->url, [
                                'module' => $split[0],
                                'controller' => $split[1],
                                'action' => $split[2]
                            ]);
                    }
                }
            }

            return $router;
        });
    }


    protected function db()
    {
        foreach (self::$_config['mysql'] as $key => $val) {
            $this->di->setShared('db_' . $key, function () use ($val) {
                return new Mysql($val->toArray());
            });
        }
    }

    protected function redis()
    {
        if (isset(self::$_config['redis'])) {
            $this->di->setShared('redis', function () {
                $redis = new \Redis();

                $redis->connect(
                    self::$_config->redis->host,
                    self::$_config->redis->port,
                    self::$_config->redis->timeout
                );
                $redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_IGBINARY);
                $redis->setOption(\Redis::OPT_PREFIX, self::$_config->project->name);
                return $redis;
            });

            /** redis数据存储非序列化版本 **/
            $this->di->setShared('redis_none_serializer', function () {
                $redis = new \Redis();

                $redis->connect(
                    self::$_config->redis->host,
                    self::$_config->redis->port,
                    self::$_config->redis->timeout
                );
                $redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_IGBINARY);
                $redis->setOption(\Redis::OPT_PREFIX, self::$_config->project->name);
                return $redis;
            });
        }
    }

    /**
     * 文件类型缓存(缓存默认值全局30秒)
     * @version APP6.3.0
     * @author lang@vip.deyi.com
     */
    protected function fileCache()
    {
        $this->di->setShared('fileCache', function () {
            return new File(new Data([
                'lifetime' => 30
            ]), [
                'cacheDir' => ROOT_PATH . '/data/cache/'
            ]);
        });
    }

    protected function memcached()
    {
        if (isset(self::$_config['memcached'])) {
            $this->di->setShared('memcached', function () {
                $memcached = new \Memcached('memcached_pool_' . self::$_config->project->name);

                if (empty($memcached->getServerList())) {
                    $memcached->setOption(\Memcached::OPT_CONNECT_TIMEOUT, 3000);
                    $memcached->setOption(\Memcached::OPT_RECV_TIMEOUT, 2000000);
                    $memcached->setOption(\Memcached::OPT_SEND_TIMEOUT, 2000000);
                    $memcached->setOption(\Memcached::OPT_POLL_TIMEOUT, 3000);
                    $memcached->setOption(\Memcached::OPT_TCP_NODELAY, true);
                    $memcached->setOption(\Memcached::OPT_DISTRIBUTION, \Memcached::DISTRIBUTION_CONSISTENT);
                    $memcached->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
                    $memcached->setOption(\Memcached::OPT_PREFIX_KEY, 'cache_' . self::$_config->project->name);
                    $memcached->setOption(\Memcached::OPT_SERIALIZER, \Memcached::SERIALIZER_PHP);
                    $memcached->setOption(\Memcached::OPT_REMOVE_FAILED_SERVERS, true);
                    $memcached->setOption(\Memcached::OPT_SERVER_FAILURE_LIMIT, 1);
                    $memcached->setOption(\Memcached::OPT_RETRY_TIMEOUT, 18000);
                    foreach (self::$_config['memcached']->toArray() as $server) {
                        $memcached->addServer($server['host'], $server['port'], $server['weight']);
                    }
                }

                return $memcached;
            });

            // 设置缓存模型服务
            $this->di->set('modelsCache', function () {
                // 共用memcached缓存设置
                return $this->di->get('memcached');
            });
        }
    }

    protected function session()
    {
        $this->di->setShared('session', function () {
            if (isset(self::$_config['memcached'])) {
                $session = new SessionCache([
                    'servers' => self::$_config['memcached']->toArray(),
                    'client' => [
                        \Memcached::OPT_PREFIX_KEY => 'sess_',
                        \Memcached::OPT_DISTRIBUTION => \Memcached::DISTRIBUTION_CONSISTENT,
                        \Memcached::OPT_LIBKETAMA_COMPATIBLE => true,
                        \Memcached::OPT_REMOVE_FAILED_SERVERS => true,
                        \Memcached::OPT_SERVER_FAILURE_LIMIT => 1,
                        \Memcached::OPT_TCP_NODELAY => 1,
                        \Memcached::OPT_RETRY_TIMEOUT => 18000
                    ],
                    'lifetime' => CacheTimeoutConstant::MONTH_CACHE
                ]);
                $session->setOptions(['uniqueId' => 'sessuid_' . self::$_config->project->name]);
            } else {
                $session = new Files([
                    'uniqueId' => 'sess_' . self::$_config->project->name
                ]);
            }

            session_set_cookie_params(CacheTimeoutConstant::MONTH_CACHE, '/', $_SERVER['HTTP_HOST'], false, true);
            $session->setName(self::$_config->project->name . '_sess');
            $session->start();

            return $session;
        });
    }

    protected function crypt()
    {
        $this->di->set('crypt', function () {
            $crypt = new Crypt();
            $crypt->setKey(self::$_config->default->secretkey);

            return $crypt;
        });
    }

    protected function loader()
    {
        $loader = new Loader();

        $loader->registerNamespaces([
            'Deyi' => ROOT_PATH . '/lib/deyi/',
            'Vendor' => ROOT_PATH . '/lib/vendor/',
            'Apps\Common' => ROOT_PATH . '/Apps/Common/',
            //----------- Es 相关
            'Elastica' => ROOT_PATH . '/lib/vendor/Elastica/',
            /**-------七牛云存储SDK--------**/
            'Qiniu' => ROOT_PATH . '/lib/vendor/Qiniu/',
            'PHPExcel' => ROOT_PATH . '/lib/vendor/PHPExcel/',
            /**-------域名解析相关------**/
            'Dns2' => ROOT_PATH . '/lib/vendor/Dns2/',
            /**-------生成二维码------**/
            'Qrcode' => ROOT_PATH . '/lib/vendor/Qrcode/',
            /**---Aliyun OSS----**/
            'OSS' => ROOT_PATH . '/lib/vendor/Aliyun/Oss/',
        ]);

        // 注册所有业务模块的命名空间
        foreach (self::$_moduleNames as $module) {
            $moduleName = ucfirst(strtolower($module));
            $loader->registerNamespaces(
                [
                    "Apps\\$moduleName\\Controllers" => ROOT_PATH . '/Apps/' . $moduleName . '/Controllers/',
                    "Apps\\$moduleName\\Models" => ROOT_PATH . '/Apps/' . $moduleName . '/Models/',
                    "Apps\\$moduleName\\Services" => ROOT_PATH . '/Apps/' . $moduleName . '/Services/'
                ],
                true
            );
        }

        $loader->register();
    }

    protected function logger()
    {
        $this->di->setShared('logger', function () {
            $logger = new FileLogger(ROOT_PATH . self::$_config->project->logpath . '.' . date('Y-m-d'));
            $logger->setSwitch(boolval(self::$_config->project->log));

            return $logger;
        });
    }

    public function beanstalkd()
    {
        $this->di->setShared('beanstalkd', function () {
            $beanstalkd = new Pheanstalk(
                self::$_config->beanstalkd->host,
                self::$_config->beanstalkd->port
            );

            return $beanstalkd;
        });
    }

    public function init()
    {
        if (isset(self::$_config->project->runmode)) {
            UserFunction::setAvatarImgUrl(self::$_config->project->runmode);
        }
    }
}
